package com.wyait.manage.config.security.filter;

import com.alibaba.fastjson.JSONObject;
import com.wyait.manage.config.security.handler.LoginFailureHandler;
import com.wyait.manage.dao.permission.OpenOauth2InfoMapper;
import com.wyait.manage.entity.ResponseResult;
import com.wyait.manage.entity.UserDTO;
import com.wyait.manage.pojo.OpenOauth2Info;
import com.wyait.manage.pojo.User;
import com.wyait.manage.service.AuthService;
import com.wyait.manage.service.UserService;
import com.wyait.manage.utils.IStatusMessage;
import lombok.SneakyThrows;
import net.sf.oval.ConstraintViolation;
import net.sf.oval.Validator;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 自定义登录过滤器
 *
 * @author xiyang.ycj
 * @since Jul 09, 2019 10:24:53 AM
 */
@Component
public class VerifyUserFilter extends OncePerRequestFilter {


    private static final Logger log = LoggerFactory.getLogger(VerifyUserFilter.class);
    @Autowired
    private UserService userService;
    @Autowired
    private AuthService authService;

    @Autowired
    private LoginFailureHandler loginFailureHandler;
    @Resource
    private OpenOauth2InfoMapper oauth2InfoMapper;

    @Resource
    private RememberMeServices rememberMeServices;
    @SneakyThrows
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
        if (request.getRequestURI().equals("/user/login")
                && request.getMethod().equalsIgnoreCase("post")) {
            try {
                validate(request);
            } catch (VerifyUserException e) {
                loginFailureHandler.onAuthenticationFailure(request, response, e);
                return;
            }
        }
        // 3. 校验通过，就放行
        filterChain.doFilter(request, response);
    }

    private void validate(HttpServletRequest request) throws Exception {
        MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
        // 将前端传递的数据转换成jsonBean数据格式
        UserDTO user = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByForm(request), UserDTO.class);
        String rememberMe1 = wrappedRequest.getParameter("rememberMe");
        boolean rememberMe = false;
        if (StringUtils.isNotBlank(rememberMe1)) {
            rememberMe = "on".equals(rememberMe1);
        }
        ResponseResult responseResult = this.login(user, rememberMe);

        if (!IStatusMessage.SystemStatus.SUCCESS.getCode().equals(responseResult.getCode())) {
            throw new VerifyUserException(responseResult.getMessage());
        }
    }

    public ResponseResult login(
            UserDTO user,
            boolean rememberMe) {
        logger.info("用户登录，请求参数=user:" + user + "，是否记住我：" + rememberMe);
        ResponseResult responseResult = new ResponseResult();
        responseResult.setCode(IStatusMessage.SystemStatus.ERROR.getCode());
        if (null == user) {
            responseResult.setCode(IStatusMessage.SystemStatus.PARAM_ERROR
                    .getCode());
            responseResult.setMessage("参数错误");
            logger.error("用户登录，结果=responseResult:" + responseResult);
            return responseResult;
        }
        if (!validatorRequestParam(user, responseResult)) {
            logger.error("用户登录，结果=responseResult:" + responseResult);
            return responseResult;
        }
        User userByUsername = this.userService.findUserByUsername(user.getUsername());
        if(Objects.isNull(userByUsername)){
            responseResult.setMessage("该用户，用户名【"+user.getUsername()+"】不存在，请您联系管理员");
            logger.error("用户登录，结果=responseResult:" + responseResult);
            return responseResult;
        }
        // 用户是否存在
        User existUser = this.userService.findUserByMobile(user.getMobile());
        if (existUser == null) {
            responseResult.setMessage("该用户,手机号【"+user.getMobile()+"】不存在，请您联系管理员");
            logger.error("用户登录，结果=responseResult:" + responseResult);
            return responseResult;
        } else {
            // 是否离职
            if (existUser.getIsJob()) {
                responseResult.setMessage("登录用户已离职，请您联系管理员");
                logger.error("用户登录，结果=responseResult:" + responseResult);
                return responseResult;
            }
            // 校验验证码

            if (!existUser.getMcode().equals(user.getSmsCode())) {
                responseResult.setCode(IStatusMessage.SystemStatus.PARAM_ERROR.getCode());
                responseResult.setMessage("短信验证码输入有误");
                logger.error("用户登录，结果=responseResult:" + responseResult);
                return responseResult;
            } //1分钟
            long beginTime = existUser.getSendTime().getTime();
            long endTime = System.currentTimeMillis();
            if (((endTime - beginTime) - 60000 > 0)) {
                responseResult.setCode(IStatusMessage.SystemStatus.PARAM_ERROR.getCode());
                responseResult.setMessage("短信验证码超时");
                logger.error("用户登录，结果=responseResult:" + responseResult);
                return responseResult;
            }
        }
        // 用户登录
        try {
            //绑定第三方账号
            String openId = user.getOpenId();
            String channelCode = user.getChannelCode();
            if (StringUtils.isNotEmpty(openId)
                    && StringUtils.isNotEmpty(channelCode)) {
                OpenOauth2Info openOauth2Info = new OpenOauth2Info();
                openOauth2Info.setUserId(existUser.getId());
                openOauth2Info.setOpenId(openId);
                openOauth2Info.setAvatar(user.getAvatar());
                openOauth2Info.setNickName(user.getNickName());
                openOauth2Info.setUpdateTime(new Date());
                openOauth2Info.setChannel(channelCode);
                OpenOauth2Info exitsOpenOauth2Info = oauth2InfoMapper.getOne(openOauth2Info.getUserId(), channelCode);
                if (Objects.isNull(exitsOpenOauth2Info)) {
                    oauth2InfoMapper.insertSelective(openOauth2Info);
                } else {
                    exitsOpenOauth2Info.setOpenId(openId);
                    exitsOpenOauth2Info.setAvatar(user.getAvatar());
                    exitsOpenOauth2Info.setNickName(user.getNickName());
                    oauth2InfoMapper.updateByPrimaryKeySelective(exitsOpenOauth2Info);
                }
            }
            responseResult.setCode(IStatusMessage.SystemStatus.SUCCESS
                    .getCode());
            logger.info("用户登录，用户验证通过！user=" + user.getMobile());
            if(rememberMe){
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                rememberMeServices.autoLogin(servletRequestAttributes.getRequest(),servletRequestAttributes.getResponse());
                System.out.println("记住我登录了");
            }
        } catch (Exception e) {
            logger.error("用户登录，用户验证未通过：操作异常，异常信息如下！user=" + user.getMobile(), e);
            responseResult.setMessage("用户登录失败，请您稍后再试");
        }
        logger.info("用户登录，user=" + user.getMobile() + ",登录结果=responseResult:"
                + responseResult);
        return responseResult;
    }

    /**
     * @param obj
     * @param response
     * @return
     * @描述：校验请求参数
     */
    protected boolean validatorRequestParam(Object obj, ResponseResult response) {
        boolean flag = false;
        Validator validator = new Validator();
        List<ConstraintViolation> ret = validator.validate(obj);
        if (ret.size() > 0) {
            // 校验参数有误
            response.setCode(IStatusMessage.SystemStatus.PARAM_ERROR.getCode());
            response.setMessage(ret.get(0).getMessageTemplate());
        } else {
            flag = true;
        }
        return flag;
    }
}
